package com.funny.exception;

import javax.servlet.http.HttpServletResponse;

/**
 * market interface of application exception.
 * 
 * @author shin1ogawa
 */
public interface ApplicationException {

	/**
	 * @return http status
	 */
	int getHttpStatus();

	/**
	 * @return errorCode
	 */
	String getErrorCode();

	/**
	 * @return errorMessage
	 */
	String getErrorMessage();

	/**
	 * @return toJson
	 */
	String toJson();


	/**
	 * default implementation for {@link ApplicationException}.
	 * 
	 * @author shin1ogawa
	 */
	@SuppressWarnings("serial")
	public static class DefaultApplicationException extends RuntimeException implements
			ApplicationException {

		private final int httpStatus;

		final String errorCode;

		final String errorMessage;


		/**
		 * the constructor.
		 * 
		 * @param httpStatus
		 * @param errorCode
		 * @param errorMessage
		 * @category constructor
		 */
		public DefaultApplicationException(int httpStatus, String errorCode, String errorMessage) {
			super(httpStatus + ":" + (errorCode == null ? "APPLICATION" : errorCode) + " "
					+ errorMessage);
			this.httpStatus = httpStatus;
			this.errorCode = errorCode == null ? "APPLICATION" : errorCode;
			this.errorMessage = errorMessage;
		}

		/**
		 * the constructor.
		 * 
		 * @param httpStatus
		 * @param errorCode
		 * @param errorMessage
		 * @param cause
		 * @category constructor
		 */
		public DefaultApplicationException(int httpStatus, String errorCode, String errorMessage,
				Throwable cause) {
			super(httpStatus + ":" + (errorCode == null ? "APPLICATION" : errorCode) + " "
					+ errorMessage, cause);
			this.httpStatus = httpStatus;
			this.errorCode = errorCode == null ? "APPLICATION" : errorCode;
			this.errorMessage = errorMessage;
		}

		@Override
		public int getHttpStatus() {
			return httpStatus;
		}

		@Override
		public String getErrorCode() {
			return errorCode;
		}

		@Override
		public String getErrorMessage() {
			return errorMessage;
		}

		@Override
		public String toJson() {
			StringBuilder b = new StringBuilder("{");
			if (errorCode == null) {
				b.append("\"code\":null");
			} else {
				b.append("\"code\":\"").append(errorCode).append("\"");
			}
			if (errorMessage == null) {
				b.append(",\"message\":null");
			} else {
				b.append(",\"message\":\"").append(errorMessage).append("\"");
			}
			b.append("}");
			return b.toString();
		}

		/**
		 * facade to throw a {@link ResourceNotFoundException}.
		 * @param resourceId
		 * @author shin1ogawa
		 */
		public static void throwResourceNotFound(String resourceId) {
			throw new ResourceNotFoundException(resourceId);
		}

		/**
		 * facade to throw a {@link BadRequestException}.
		 * @param message
		 * @author shin1ogawa
		 */
		public static void throwBadRequst(String message) {
			throw new BadRequestException(message);
		}

		/**
		 * facade to throw a {@link UnAuthorizedException}.
		 * @param loginURL
		 * @author shin1ogawa
		 */
		public static void throwUnAuthorized(String loginURL) {
			throw new UnAuthorizedException(loginURL);
		}
	}

	/**
	 * 400.
	 * @author shin1ogawa
	 */
	@SuppressWarnings("serial")
	public static class BadRequestException extends DefaultApplicationException {

		/**
		 * the constructor.
		 * @param errorMessage
		 * @category constructor
		 */
		public BadRequestException(String errorMessage) {
			super(HttpServletResponse.SC_BAD_REQUEST, "BAD_REQUEST", errorMessage);
		}
	}

	/**
	 * 401.
	 * @author shin1ogawa
	 */
	@SuppressWarnings("serial")
	public static class UnAuthorizedException extends DefaultApplicationException {

		/**
		 * the constructor.
		 * @param loginURL the url for login
		 * @category constructor
		 */
		public UnAuthorizedException(String loginURL) {
			super(HttpServletResponse.SC_UNAUTHORIZED, "UNAUTHORIZED", loginURL);
		}
	}

	/**
	 * 404.
	 * @author shin1ogawa
	 */
	@SuppressWarnings("serial")
	public static class ResourceNotFoundException extends DefaultApplicationException {

		/**
		 * the constructor.
		 * @param errorMessage
		 * @category constructor
		 */
		public ResourceNotFoundException(String errorMessage) {
			super(HttpServletResponse.SC_NOT_FOUND, "NOT_FOUND", errorMessage);
		}
	}
}
